/**
 * Copyright (C) 2016-2019 DSpot Sp. z o.o
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dspot.declex;

import com.dspot.declex.action.Actions;
import com.dspot.declex.adapter.plugin.JClassPlugin;
import com.dspot.declex.handler.ActionForHandler;
import com.dspot.declex.handler.AdapterClassHandler;
import com.dspot.declex.handler.AfterLoadHandler;
import com.dspot.declex.handler.AfterPutHandler;
import com.dspot.declex.handler.EventHandler;
import com.dspot.declex.handler.ExportHandler;
import com.dspot.declex.handler.ExportedHandler;
import com.dspot.declex.handler.ExportedPopulateHandler;
import com.dspot.declex.handler.ExportedRecollectHandler;
import com.dspot.declex.handler.ImportHandler;
import com.dspot.declex.handler.JsonModelHandler;
import com.dspot.declex.handler.LoadOnEventHandler;
import com.dspot.declex.handler.LocalDBModelHandler;
import com.dspot.declex.handler.LocalDBTransactionHandler;
import com.dspot.declex.handler.ModelHandler;
import com.dspot.declex.handler.OnEventHandler;
import com.dspot.declex.handler.PopulateHandler;
import com.dspot.declex.handler.PutOnActionHandler;
import com.dspot.declex.handler.PutOnEventHandler;
import com.dspot.declex.handler.RecollectHandler;
import com.dspot.declex.handler.RunWithHandler;
import com.dspot.declex.handler.ServerModelHandler;
import com.dspot.declex.handler.UpdateOnEventHandler;
import com.dspot.declex.handler.UseEventsHandler;
import com.dspot.declex.handler.UseLocalDBHandler;
import com.dspot.declex.handler.UseModelHandler;
import com.dspot.declex.holder.UseModelHolder;
import com.dspot.declex.override.handler.AfterInjectHandler;
import com.dspot.declex.override.handler.AfterViewsHandler;
import com.dspot.declex.override.handler.BackgroundHandler;
import com.dspot.declex.override.handler.CheckedChangeHandler;
import com.dspot.declex.override.handler.ClickHandler;
import com.dspot.declex.override.handler.EAbilityHandler;
import com.dspot.declex.override.handler.EApplicationHandler;
import com.dspot.declex.override.handler.EBeanHandler;
import com.dspot.declex.override.handler.EFractionHandler;
import com.dspot.declex.override.handler.EIntentServiceHandler;
import com.dspot.declex.override.handler.EProviderHandler;
import com.dspot.declex.override.handler.EReceiverHandler;
import com.dspot.declex.override.handler.EServiceHandler;
import com.dspot.declex.override.handler.EViewGroupHandler;
import com.dspot.declex.override.handler.EViewHandler;
import com.dspot.declex.override.handler.EditorActionHandler;
import com.dspot.declex.override.handler.ExtraHandler;
import com.dspot.declex.override.handler.FocusChangeHandler;
import com.dspot.declex.override.handler.FragmentArgHandler;
import com.dspot.declex.override.handler.InstanceStateHandler;
import com.dspot.declex.override.handler.ItemClickHandler;
import com.dspot.declex.override.handler.ItemLongClickHandler;
import com.dspot.declex.override.handler.LongClickHandler;
import com.dspot.declex.override.handler.ServiceActionHandler;
import com.dspot.declex.override.handler.UiThreadHandler;
import com.dspot.declex.util.SharedRecords;

import org.ohosannotations.OhosAnnotationsEnvironment;
import org.ohosannotations.Option;
import org.ohosannotations.handler.AnnotationHandler;
import org.ohosannotations.internal.core.handler.AfterExtrasHandler;
import org.ohosannotations.internal.core.handler.AfterPreferencesHandler;
import org.ohosannotations.internal.core.handler.AnimationResHandler;
import org.ohosannotations.internal.core.handler.AppHandler;
import org.ohosannotations.internal.core.handler.BeanHandler;
import org.ohosannotations.internal.core.handler.BindingObjectHandler;
import org.ohosannotations.internal.core.handler.ColorResHandler;
import org.ohosannotations.internal.core.handler.ColorStateListResHandler;
import org.ohosannotations.internal.core.handler.ComponentByIdHandler;
import org.ohosannotations.internal.core.handler.ComponentsByIdHandler;
import org.ohosannotations.internal.core.handler.CustomTitleHandler;
import org.ohosannotations.internal.core.handler.DataBoundHandler;
import org.ohosannotations.internal.core.handler.DefaultResHandler;
import org.ohosannotations.internal.core.handler.FractionByIdHandler;
import org.ohosannotations.internal.core.handler.FractionByTagHandler;
import org.ohosannotations.internal.core.handler.FromHtmlHandler;
import org.ohosannotations.internal.core.handler.FullscreenHandler;
import org.ohosannotations.internal.core.handler.HierarchyViewerSupportHandler;
import org.ohosannotations.internal.core.handler.HtmlResHandler;
import org.ohosannotations.internal.core.handler.HttpsClientHandler;
import org.ohosannotations.internal.core.handler.IgnoreWhenHandler;
import org.ohosannotations.internal.core.handler.InjectMenuHandler;
import org.ohosannotations.internal.core.handler.ItemSelectHandler;
import org.ohosannotations.internal.core.handler.KeyDownHandler;
import org.ohosannotations.internal.core.handler.KeyLongPressHandler;
import org.ohosannotations.internal.core.handler.KeyMultipleHandler;
import org.ohosannotations.internal.core.handler.KeyUpHandler;
import org.ohosannotations.internal.core.handler.NonConfigurationInstanceHandler;
import org.ohosannotations.internal.core.handler.OnAbilityResultHandler;
import org.ohosannotations.internal.core.handler.PageScrollStateChangedHandler;
import org.ohosannotations.internal.core.handler.PageScrolledHandler;
import org.ohosannotations.internal.core.handler.PageSelectedHandler;
import org.ohosannotations.internal.core.handler.PixelMapResHandler;
import org.ohosannotations.internal.core.handler.PrefHandler;
import org.ohosannotations.internal.core.handler.PreferenceByKeyHandler;
import org.ohosannotations.internal.core.handler.PreferenceChangeHandler;
import org.ohosannotations.internal.core.handler.PreferenceClickHandler;
import org.ohosannotations.internal.core.handler.PreferenceHeadersHandler;
import org.ohosannotations.internal.core.handler.PreferenceScreenHandler;
import org.ohosannotations.internal.core.handler.ReceiverActionHandler;
import org.ohosannotations.internal.core.handler.ReceiverHandler;
import org.ohosannotations.internal.core.handler.RootContextHandler;
import org.ohosannotations.internal.core.handler.SharedPrefHandler;
import org.ohosannotations.internal.core.handler.SliderProgressUpdatedHandler;
import org.ohosannotations.internal.core.handler.SliderTouchEndHandler;
import org.ohosannotations.internal.core.handler.SliderTouchStartHandler;
import org.ohosannotations.internal.core.handler.SupposeBackgroundHandler;
import org.ohosannotations.internal.core.handler.SupposeThreadHandler;
import org.ohosannotations.internal.core.handler.SupposeUiThreadHandler;
import org.ohosannotations.internal.core.handler.SystemServiceHandler;
import org.ohosannotations.internal.core.handler.TextUpdatedHandler;
import org.ohosannotations.internal.core.handler.TouchHandler;
import org.ohosannotations.internal.core.handler.TraceHandler;
import org.ohosannotations.internal.core.handler.TransactionalHandler;
import org.ohosannotations.internal.core.handler.WindowFeatureHandler;
import org.ohosannotations.internal.core.model.OhosRes;
import org.ohosannotations.plugin.OhosAnnotationsPlugin;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class DeclexCorePlugin extends OhosAnnotationsPlugin {

    private static final String DECLEX_ISSUES_URL = "https://github.com/smaugho/declex/issues";

    private static final String NAME = "DecleX";

    public DeclexCorePlugin() {
        SharedRecords.reset();
    }

    @Override
    public String getIssuesUrl() {
        return DECLEX_ISSUES_URL;
    }

    @Override
    public String getName() {
        return NAME;
    }

    @Override
    public List<Option> getSupportedOptions() {
        return Arrays.asList(

            TraceHandler.OPTION_TRACE,
            SupposeThreadHandler.OPTION_THREAD_CONTROL,

            UseModelHolder.OPTION_GENERATE_IS_GETTERS,

            Actions.OPTION_DEBUG_ACTIONS

        );
    }

    @Override
    public List<AnnotationHandler<?>> getHandlers(OhosAnnotationsEnvironment ohosAnnotationEnv) {

        List<AnnotationHandler<?>> annotationHandlers = new LinkedList<>();

        //Generating Annotations Handlers
        annotationHandlers.add(new EApplicationHandler(ohosAnnotationEnv));
        annotationHandlers.add(new EAbilityHandler(ohosAnnotationEnv));
        annotationHandlers.add(new EProviderHandler(ohosAnnotationEnv));
        annotationHandlers.add(new EReceiverHandler(ohosAnnotationEnv));
        annotationHandlers.add(new EServiceHandler(ohosAnnotationEnv));
        annotationHandlers.add(new EIntentServiceHandler(ohosAnnotationEnv));
        annotationHandlers.add(new EFractionHandler(ohosAnnotationEnv));
        annotationHandlers.add(new EBeanHandler(ohosAnnotationEnv));
        annotationHandlers.add(new EViewGroupHandler(ohosAnnotationEnv));
        annotationHandlers.add(new EViewHandler(ohosAnnotationEnv));
        annotationHandlers.add(new SharedPrefHandler(ohosAnnotationEnv));

        annotationHandlers.add(new ActionForHandler(ohosAnnotationEnv));

        //Events Handlers
        annotationHandlers.add(new EventHandler(ohosAnnotationEnv));
        annotationHandlers.add(new OnEventHandler(ohosAnnotationEnv));
        annotationHandlers.add(new UpdateOnEventHandler(ohosAnnotationEnv));
        annotationHandlers.add(new LoadOnEventHandler(ohosAnnotationEnv));
        annotationHandlers.add(new PutOnEventHandler(ohosAnnotationEnv));
        annotationHandlers.add(new PutOnActionHandler(ohosAnnotationEnv));
        annotationHandlers.add(new UseEventsHandler(ohosAnnotationEnv));

        //Model Handlers
        annotationHandlers.add(new UseModelHandler(ohosAnnotationEnv));
        annotationHandlers.add(new AfterLoadHandler(ohosAnnotationEnv));
        annotationHandlers.add(new AfterPutHandler(ohosAnnotationEnv));
        annotationHandlers.add(new JsonModelHandler(ohosAnnotationEnv));
        annotationHandlers.add(new LocalDBModelHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ServerModelHandler(ohosAnnotationEnv));
        annotationHandlers.add(new UseLocalDBHandler(ohosAnnotationEnv));

        annotationHandlers.add(new LocalDBTransactionHandler(ohosAnnotationEnv));

        //Main Injection Handlers
        annotationHandlers.add(new PrefHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ComponentByIdHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ComponentsByIdHandler(ohosAnnotationEnv));
        annotationHandlers.add(new FractionByIdHandler(ohosAnnotationEnv));
        annotationHandlers.add(new FractionByTagHandler(ohosAnnotationEnv));
        annotationHandlers.add(new FromHtmlHandler(ohosAnnotationEnv));

        annotationHandlers.add(new AppHandler(ohosAnnotationEnv));
        annotationHandlers.add(new BeanHandler(ohosAnnotationEnv));

        //Parameters Injection Handler
        annotationHandlers.add(new FragmentArgHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ExtraHandler(ohosAnnotationEnv));
        annotationHandlers.add(new BindingObjectHandler(ohosAnnotationEnv));

        //Actions and its plugins
        annotationHandlers.add(new RunWithHandler<>(ohosAnnotationEnv));

        //Listeners Handlers
        annotationHandlers.add(new ClickHandler(ohosAnnotationEnv));
        annotationHandlers.add(new LongClickHandler(ohosAnnotationEnv));
        annotationHandlers.add(new TouchHandler(ohosAnnotationEnv));
        annotationHandlers.add(new FocusChangeHandler(ohosAnnotationEnv));
        annotationHandlers.add(new CheckedChangeHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ItemClickHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ItemSelectHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ItemLongClickHandler(ohosAnnotationEnv));
        annotationHandlers.add(new EditorActionHandler(ohosAnnotationEnv));

        for (OhosRes ohosRes : OhosRes.values()) {
            if (ohosRes == OhosRes.ANIMATION) {
                annotationHandlers.add(new AnimationResHandler(ohosAnnotationEnv));
            } else if (ohosRes == OhosRes.COLOR) {
                annotationHandlers.add(new ColorResHandler(ohosAnnotationEnv));
            } else if (ohosRes == OhosRes.COLOR_STATE_LIST) {
                annotationHandlers.add(new ColorStateListResHandler(ohosAnnotationEnv));
            } else if (ohosRes == OhosRes.PIXEL_MAP) {
                annotationHandlers.add(new PixelMapResHandler(ohosAnnotationEnv));
            } else if (ohosRes == OhosRes.HTML) {
                annotationHandlers.add(new HtmlResHandler(ohosAnnotationEnv));
            } else {
                annotationHandlers.add(new DefaultResHandler(ohosRes, ohosAnnotationEnv));
            }
        }

        annotationHandlers.add(new TransactionalHandler(ohosAnnotationEnv));
        annotationHandlers.add(new SystemServiceHandler(ohosAnnotationEnv));

        annotationHandlers.add(new NonConfigurationInstanceHandler(ohosAnnotationEnv));
        annotationHandlers.add(new InjectMenuHandler(ohosAnnotationEnv));
/*		annotationHandlers.add(new OptionsMenuHandler(ohosAnnotationEnv));
		annotationHandlers.add(new OptionsMenuItemHandler(ohosAnnotationEnv));
		annotationHandlers.add(new OptionsItemHandler(ohosAnnotationEnv));*/

        annotationHandlers.add(new CustomTitleHandler(ohosAnnotationEnv));
        annotationHandlers.add(new FullscreenHandler(ohosAnnotationEnv));
        annotationHandlers.add(new RootContextHandler(ohosAnnotationEnv));
		
		/*annotationHandlers.add(new BeforeTextChangeHandler(ohosAnnotationEnv));
		annotationHandlers.add(new TextChangeHandler(ohosAnnotationEnv));
		annotationHandlers.add(new AfterTextChangeHandler(ohosAnnotationEnv));*/
        annotationHandlers.add(new TextUpdatedHandler(ohosAnnotationEnv));
        annotationHandlers.add(new SliderProgressUpdatedHandler(ohosAnnotationEnv));
        annotationHandlers.add(new SliderTouchStartHandler(ohosAnnotationEnv));
        annotationHandlers.add(new SliderTouchEndHandler(ohosAnnotationEnv));
        annotationHandlers.add(new KeyDownHandler(ohosAnnotationEnv));
        annotationHandlers.add(new KeyLongPressHandler(ohosAnnotationEnv));
        annotationHandlers.add(new KeyMultipleHandler(ohosAnnotationEnv));
        annotationHandlers.add(new KeyUpHandler(ohosAnnotationEnv));

        annotationHandlers.add(new ServiceActionHandler(ohosAnnotationEnv));
        annotationHandlers.add(new InstanceStateHandler(ohosAnnotationEnv));
        annotationHandlers.add(new HttpsClientHandler(ohosAnnotationEnv));
        annotationHandlers.add(new HierarchyViewerSupportHandler(ohosAnnotationEnv));
        annotationHandlers.add(new WindowFeatureHandler(ohosAnnotationEnv));

        annotationHandlers.add(new ReceiverHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ReceiverActionHandler(ohosAnnotationEnv));
        annotationHandlers.add(new OnAbilityResultHandler(ohosAnnotationEnv));

        annotationHandlers.add(new PageScrolledHandler(ohosAnnotationEnv));
        annotationHandlers.add(new PageScrollStateChangedHandler(ohosAnnotationEnv));
        annotationHandlers.add(new PageSelectedHandler(ohosAnnotationEnv));

        annotationHandlers.add(new IgnoreWhenHandler(ohosAnnotationEnv));

        //Populators, Recollectors and Injected Models
        annotationHandlers.add(new RecollectHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ModelHandler(ohosAnnotationEnv));

        List<JClassPlugin> adapterPlugins = new LinkedList<JClassPlugin>();

        //View Features Handler
        AdapterClassHandler adapterClassHandler = new AdapterClassHandler(ohosAnnotationEnv);
        annotationHandlers.add(adapterClassHandler);
        adapterPlugins.add(adapterClassHandler);

        annotationHandlers.add(new PopulateHandler(ohosAnnotationEnv, adapterPlugins));

        /* After injection methods must be after injections */
        annotationHandlers.add(new AfterInjectHandler(ohosAnnotationEnv));
        annotationHandlers.add(new AfterExtrasHandler(ohosAnnotationEnv));
        annotationHandlers.add(new AfterViewsHandler(ohosAnnotationEnv));

        annotationHandlers.add(new PreferenceScreenHandler(ohosAnnotationEnv));
        annotationHandlers.add(new PreferenceHeadersHandler(ohosAnnotationEnv));
        annotationHandlers.add(new PreferenceByKeyHandler(ohosAnnotationEnv));
        annotationHandlers.add(new PreferenceChangeHandler(ohosAnnotationEnv));
        annotationHandlers.add(new PreferenceClickHandler(ohosAnnotationEnv));
        annotationHandlers.add(new AfterPreferencesHandler(ohosAnnotationEnv));

        annotationHandlers.add(new DataBoundHandler(ohosAnnotationEnv));

        annotationHandlers.add(new TraceHandler(ohosAnnotationEnv));

        /*
         * WakeLockHandler must be after TraceHandler but before UiThreadHandler
         * and BackgroundHandler
         */
        //annotationHandlers.add(new WakeLockHandler(ohosAnnotationEnv));

        /*
         * UIThreadHandler and BackgroundHandler must be after TraceHandler and
         * IgnoredWhenDetached
         */
        annotationHandlers.add(new UiThreadHandler(ohosAnnotationEnv));
        annotationHandlers.add(new BackgroundHandler(ohosAnnotationEnv));

        /*
         * SupposeUiThreadHandler and SupposeBackgroundHandler must be after all
         * handlers that modifies generated method body
         */
        annotationHandlers.add(new SupposeUiThreadHandler(ohosAnnotationEnv));
        annotationHandlers.add(new SupposeBackgroundHandler(ohosAnnotationEnv));

        //DependencyHandler should be one of the last, in order to permit
        //the generation of all the methods which would be generated
        annotationHandlers.add(new ImportHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ExportHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ExportedHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ExportedPopulateHandler(ohosAnnotationEnv));
        annotationHandlers.add(new ExportedRecollectHandler(ohosAnnotationEnv));

        return annotationHandlers;
    }

}
